
/*
 * Input Example
 *
 * Desc: a simple example to monitor key: ctrl+#
 * Usage: (./test.sh)
 *   insmod drv
 *   qemu: sendkey ctrl-shift-3
 *   virsh: virsh send-key my-vm KEY_LEFTCTRL KEY_SHIFT KEY_3
 *   rmmod drv
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/init.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>

#include <linux/input.h>


static struct input_handle key_handle;
static bool ctrl_pressed, shift_pressed;

//If need filter, return 1, else return 0.
//Since we just monitor key: ctrl+shift+3, so we don't need to filter
static bool key_filter(struct input_handle *handle,
			 unsigned int type, unsigned int code, int value)
{
	//pr_info("type=%d, code=%d, value=%d\n", type, code, value);

	if (type != EV_KEY)
		return 0;

	if (code == KEY_LEFTCTRL && value == 1)
		ctrl_pressed = true;

	if (code == KEY_LEFTSHIFT && value == 1)
		shift_pressed = true;

	if (code == KEY_3 && value == 1) {
		if (ctrl_pressed && shift_pressed)
			pr_info("Pressed Key: Ctrl + #\n");
		ctrl_pressed = shift_pressed = false;
	}

	return 0;
}


static int key_connect(struct input_handler *handler, struct input_dev *dev,
	const struct input_device_id *id)
{
	int ret;

	key_handle.dev = dev;
	key_handle.handler = handler;
	key_handle.name = "mykey";

	ret = input_register_handle(&key_handle);
	if (ret) {
		pr_err("%s: input_register_handle failed, ret=%d\n", __func__, ret);
		return ret;
	}

	ret = input_open_device(&key_handle);
	if (ret) {
		pr_err("%s: input_open_device failed, ret=%d\n", __func__, ret);
		input_unregister_handle(&key_handle);
		return ret;
	}

	return 0;
}

static void key_disconnect(struct input_handle *handle)
{
	input_close_device(&key_handle);
	input_unregister_handle(&key_handle);
}


static struct input_device_id key_ids[] = {
	{
		.flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT,
		.evbit = { [BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY) },
		.keybit = {  //这里似乎并不能做按键的过滤
			[BIT_WORD(KEY_LEFTCTRL)] = BIT_MASK(KEY_LEFTCTRL),
			[BIT_WORD(KEY_LEFTSHIFT)] = BIT_MASK(KEY_LEFTSHIFT),
			[BIT_WORD(KEY_3)] = BIT_MASK(KEY_3),
		},
	},
	{},
};


static struct input_handler key_handler = {
	.filter	= key_filter,
	.connect = key_connect,
	.disconnect = key_disconnect,
	.name = "my_key_handler",
	.id_table = key_ids,
};

static int __init mydrv_init(void)
{
	pr_info("%s...\n", __func__);


	return input_register_handler(&key_handler);
}

static void __exit mydrv_exit(void)
{
	pr_info("%s...\n", __func__);

	input_unregister_handler(&key_handler);
}

module_init(mydrv_init);
module_exit(mydrv_exit);

MODULE_AUTHOR("mydrv");
MODULE_LICENSE("GPL");
